﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using StockFinder.Model;
using StockFinder.Indicators;
using log4net;

namespace StockFinder.Services.PriceAnalysis
{
    public class JustBrokenOutPriceAnalyser : IPriceAnalyser
    {
        private static readonly ILog _Log = LogManager.GetLogger(typeof(JustBrokenOutPriceAnalyser)); 

        public PriceAnalysisResult RunAnalysis(IOrderedEnumerable<DailyPrice> prices)
        {
            PriceAnalysisResult result = new PriceAnalysisResult();

            if (prices.Count() > 0)
            {
                //get last price
                DailyPrice lastPrice = prices.ElementAt(0);

                result.MostRecentPriceDate = lastPrice.PriceDate;

                //make sure this has a price history, and not IPO day
                if (prices.Count() > 1)
                {
                    try
                    {
                        /* is the previouse close higher than any previous high */                        

                        //get all time high before today
                        DailyPrice allTimeHigh = prices.Skip(1).AllTimeHighestPriceByAdjustedHigh();

                        //is the last price close higher than the previous all time high?
                        if (lastPrice.AdjustedClose > allTimeHigh.AdjustedHigh)
                        {
                            //yes we have broken out, now get base details
                            //4. get all prices since all time high
                            IEnumerable<DailyPrice> baseSinceAllTimeHigh = prices.Where(i => i.PriceDate >= allTimeHigh.PriceDate);

                            //5. make sure there are no 0 prices
                            if (!baseSinceAllTimeHigh.Any(i => i.AdjustedLow == 0))
                            {
                                //6. get the low of the base
                                decimal baseLow = baseSinceAllTimeHigh.Min(i => i.AdjustedLow);

                                //7. the daily price for that low
                                DailyPrice baseLowPrice = baseSinceAllTimeHigh.First(i => i.AdjustedLow == baseLow);

                                TimeSpan timeInBase = lastPrice.PriceDate - allTimeHigh.PriceDate;

                                int daysInBase = timeInBase.Days;

                                //determine the base depth
                                decimal baseDepth = (allTimeHigh.AdjustedHigh - baseLow) / allTimeHigh.AdjustedHigh * 100;

                                decimal sma50 = prices.GetSimpleMovingAverage(50);

                                if (sma50 > 0)
                                {
                                    decimal percentFromSMA50 = lastPrice.AdjustedClose - sma50;

                                    percentFromSMA50 = (percentFromSMA50 / sma50) * 100;

                                    result.PercentFrom50SMA = percentFromSMA50;
                                }

                                //set diagnostics
                                result.Succeeded = true;
                                result.BaseDepth = baseDepth;
                                result.BaseLength = baseSinceAllTimeHigh.Count();
                                result.BaseLow = baseLow;
                                result.BaselowDate = baseLowPrice.PriceDate;
                                result.DaysOfPrices = prices.Count();
                                result.PreviousHigh = allTimeHigh.AdjustedHigh;
                                result.PreviousHighDate = allTimeHigh.PriceDate;                                
                            }
                            else
                            {
                                _Log.Warn("Contains a 0 price, skipping");
                            }
                        }
                    }
                    catch (Exception exception)
                    {
                        _Log.Error(exception);
                    }
                }
            }
            else
            {
                _Log.Warn("No prices, skipping");
            }

            return result;
        }
    }
}
